#include "StdAfx.h"
#include "MD5Generate.h"
#pragma pack (1)

std::wstring getPathName(const wchar_t* fullName)
{
	if(fullName == NULL)
		return L"";
	std::wstring _ret = fullName;   
	std::wstring::size_type pos = _ret.rfind('\\');
	std::wstring _ext = L"\\";
	if(pos == std::wstring::npos) 
	{
		pos = _ret.rfind('/');
		_ext = L"/";
	}
	if(pos == std::wstring::npos )
	{
		return L"";
	}

	_ret.replace(pos ,wcslen(fullName), L"");
	return _ret + _ext;
}

CMD5Generate::CMD5Generate(void)
{
}

CMD5Generate::~CMD5Generate(void)
{
}

bool isNum( wchar_t ch )
{
	if ( ch >= 48 && ch <= 58 )
		return true;
	else
		return false;
}

void CMD5Generate::GenerateMD5( const wchar_t* file_name )
{
	if ( NULL == file_name )
		return;

	wchar_t strPath[MAX_PATH] = _T("");
	DWORD dwTest;
	//::GetModuleFileName(hInstance, strPath, MAX_PATH);
	dwTest = ::GetModuleFileName(NULL, strPath, MAX_PATH);
	
	
	std::wstring strAbsPath = getPathName( strPath );

	std::wstring strInFileName = strAbsPath;
	strInFileName += file_name;

	float file_size = 0.0f;
	std::wstring strMD5 = DigestFile( strInFileName.c_str(), file_size);
	
	std::wstring strMD5NoNumber = L" ";
	for ( int i=0; i<strMD5.length(); i++ )
	{
		if ( !isNum( strMD5.at(i)))
			strMD5NoNumber += strMD5.at(i);
	}
	std::wstring strOutFile = strInFileName;
	strOutFile += L".txt";
	FILE *fp = NULL;
	fp = _wfopen( strOutFile.c_str(), L"w+t");
	int numwritten = fwrite( strMD5.c_str(), sizeof( wchar_t ), strMD5.length(), fp );
	numwritten = fwrite( strMD5NoNumber.c_str(), sizeof( wchar_t ), strMD5NoNumber.length(), fp );
	fclose(fp);

}


std::wstring CMD5Generate::Digest( BYTE* buffer, long len )
{
	CString csDigest;
	HCRYPTPROV hCryptProv;
	HCRYPTHASH hHash;
	BYTE bHash[0x7f];

	DWORD dwHashLen = 16;

	DWORD cbContent= len; 
	BYTE* pbContent= buffer; 

	if(CryptAcquireContext(&hCryptProv, 
		NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) 
	{
		if(CryptCreateHash(hCryptProv,CALG_MD5,0, 0, &hHash)) 
		{
			if(CryptHashData(hHash, pbContent, cbContent, 0))
			{

				if(CryptGetHashParam(hHash, HP_HASHVAL, bHash, &dwHashLen, 0)) 
				{
					csDigest.Empty();
					CString tmp;
					for (int i = 0; i<16; i++)
					{
						tmp.Format(L"%02x", bHash[i]);
						csDigest+=tmp;
					}

				}
				else 
					csDigest=_T("Error getting hash param");

			}
			else 
				csDigest=_T("Error hashing data"); 
		}
		else 
			csDigest=_T("Error creating hash"); 
	}
	else 
		csDigest=_T("Error acquiring context");

	CryptDestroyHash(hHash); 
	CryptReleaseContext(hCryptProv, 0); 
//	csBuffer.ReleaseBuffer();

	std::wstring strDigest = csDigest.GetBuffer();
	return strDigest;
}

std::wstring CMD5Generate::Digest(CString& csBuffer)
{
	CString csDigest;
	HCRYPTPROV hCryptProv;
	HCRYPTHASH hHash;
	BYTE bHash[0x7f];

	DWORD dwHashLen = 16;

	DWORD cbContent= csBuffer.GetLength(); 
	BYTE* pbContent= (BYTE*)csBuffer.GetBuffer(cbContent); 

	if(CryptAcquireContext(&hCryptProv, 
		NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) 
	{
			if(CryptCreateHash(hCryptProv,CALG_MD5,0, 0, &hHash)) 
			{
				if(CryptHashData(hHash, pbContent, cbContent, 0))
				{

					if(CryptGetHashParam(hHash, HP_HASHVAL, bHash, &dwHashLen, 0)) 
					{
						csDigest.Empty();
						CString tmp;
						for (int i = 0; i<16; i++)
						{
							tmp.Format(L"%02x", bHash[i]);
							csDigest+=tmp;
						}

					}
					else 
						csDigest=_T("Error getting hash param");

				}
				else 
					csDigest=_T("Error hashing data"); 
			}
			else 
				csDigest=_T("Error creating hash"); 
	}
	else 
		csDigest=_T("Error acquiring context");

	CryptDestroyHash(hHash); 
	CryptReleaseContext(hCryptProv, 0); 
	csBuffer.ReleaseBuffer();

	std::wstring strDigest = csDigest.GetBuffer();
	return strDigest;
}

std::wstring CMD5Generate::DigestFile(const wchar_t* file_name, float &file_size)
{
	std::wstring strDigest = L"";
	if ( NULL == file_name  )
		return strDigest;

	//CFile file;
	//file.Open( file_name, CFile::modeRead );
	//long len = file.GetLength();
	////file.GetBufferPtr()
	//wchar_t* buffer = new wchar_t(len);
	//
	//file.Read( buffer, len );
	/////////////////////////////////////
	FILE *fp = NULL;
	fp = _wfopen( file_name, L"rb");
	if ( NULL == fp )
		return strDigest;
	
	fseek( fp, 0, SEEK_END);
	long len = ftell(fp);
	fseek( fp, 0, SEEK_SET);
	
	
	char* buffer = new char[len];
	fread(buffer, sizeof(char),len, fp );

	fclose(fp);
//	CString strBuffer(buffer);

	strDigest = Digest( (BYTE*)buffer, len );

	file_size = (float)len / float(1024 * 1024);
	delete buffer;
	return strDigest;
}

